package com.wzy.single;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

/**
 * Created with IntelliJ IDEA.
 *
 * @Auther: wzy
 * @Date: 2021/09/13/18:18
 * @Description: 懒汉式
 */
public class LazySingleton {

    private static boolean wzy = false;

    private LazySingleton() {
        // 解决一个用getInstance 一个用反射
        synchronized (LazySingleton.class) {
            // 红绿灯 解决两个都用反射创建对象  还是不安全的
            if (wzy == false) {
                wzy = true;
            } else {
                throw new RuntimeException("不要试图通过反射破坏");
            }
            if (singleton != null) {
                throw new RuntimeException("该对象已经存在！！");
            }
        }
        System.out.println(Thread.currentThread().getName() + "---OK");
    }

    ;

    private static volatile LazySingleton singleton;

    public static LazySingleton getInstance() {
        // 双重检测锁模式的懒汉式  DCL懒汉式
        if (singleton == null) {
            synchronized (LazySingleton.class) {
                if (singleton == null) {
                    singleton = new LazySingleton();
                    /**
                     * 会有问题：不是原子性操作
                     * 1. 分配内存空间
                     * 2. 执行构造方法，初始化对象
                     * 3. 对象指向该空间
                     *
                     * 指令重拍
                     * 期望：123
                     * 可能  132  此时single 还没有完成构造 所以要加 volatile 防止指令重排
                     */
                }
            }
        }
        return singleton;
    }

    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        LazySingleton instance = LazySingleton.getInstance();
        Constructor<LazySingleton> declaredConstructor = LazySingleton.class.getDeclaredConstructor(null);
        declaredConstructor.setAccessible(true);
        LazySingleton instance1 = declaredConstructor.newInstance();
        LazySingleton instance2 = declaredConstructor.newInstance();
//        System.out.println(instance);
        System.out.println(instance1);
        System.out.println(instance2);




        /*for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                LazySingleton.getInstance();
            }).start();
        }*/
    }
}
